#include "Type.h"
#include "FunctionList.h"
#include "NativeFunction.h"
#include "StringSerializable.h"
#include "TypeInstance.h"


#include "Enum.h"


CType* CGetType<bool>:: operator() ()
{
    class CBoolType: public CType
    {
    public:
        CBoolType()
        : CType(STypeID(U"bool",true)
        , ETypeFlags::Basic | ETypeFlags::ScriptInner
        )
        {
            Instancable=new CBoolInstance(this);
            StringSerializable=new CBoolStringSerializable();
            Functions= new CFunctionList(this);
            {
                auto ToStringFunction = new CNativeFunction(Functions,U"ToString",CGetType<CString>()(),{},{});
                ToStringFunction->SetCppBody([](const TVector<CAny>& InArgs)->CAny
                {
                    bool Value= **reinterpret_cast<const bool**>(InArgs[0].GetPointer());
                    return CString(Value?U"true":U"false");
                });

                Functions->VirtualFunctionTable.Add(ToStringFunction->ID);
            }
        }

    protected:
        class CBoolInstance: public ITypeInstance
        {
        protected:
            CType* BoolType;
        public:
            CBoolInstance(CType* InBoolType)
            {
                BoolType=InBoolType;
            }

            virtual CString ToDebugString(const void * InInstance) const override
            {
                bool Value= *reinterpret_cast<const bool*>(InInstance);
                return Value?U"true":U"false";                
            }

            virtual uint32_t GetSize() override
            {
                return sizeof(bool);
            }

            virtual uint64_t GetInstanceHash(const void * Instance) const override
            {
                return *reinterpret_cast<const bool*>(Instance);
            }

            virtual bool IsForceConvertableTo(CType * Other) override
            { 
                if(Other==BoolType)
                {
                    return true;
                }
                return false;
            }
            
            virtual bool IsInstanceEqual(const void * Instance0,const void * Instance1) const
            {
                return *reinterpret_cast<const bool*>(Instance0)==*reinterpret_cast<const bool*>(Instance1);
            }

            virtual void InitInstance(void* Memory) override
            {
                *reinterpret_cast<bool*>(Memory)=false;
            }

            virtual void EraseInstance(void* Instance) override
            {
                //do nothing
            }
            virtual void CloneInstance(const void* Instance,void * TargetMemory) override
            {
                *reinterpret_cast<bool*>(TargetMemory)=*reinterpret_cast<const bool*>(Instance);
            }
            //allocate memory for this type in script
            //for inner type , just give a 0.
            //for class type , give a nullptr .
            //for struct type , give a list of Allocated field.
            virtual void* CreateInstance() override
            {
                return new bool(false);
            }
            
            
            virtual void ResetAllocated(void* Memory) override
            {
                *reinterpret_cast<bool*>(Memory)=false;
            }

        };

        class CBoolStringSerializable: public IStringSerializable
        {
        public:
            virtual CString ToString(const void* InInstance) const override
            {
                bool Value= *reinterpret_cast<const bool*>(InInstance);
                return Value?U"true":U"false";
            }
            virtual void FromString(const CString& InString,void * InInstance) const override
            {
                if(InString==U"true")
                {
                    *reinterpret_cast<bool*>(InInstance)=true;
                }
                else if(InString==U"false")
                {
                    *reinterpret_cast<bool*>(InInstance)=false;
                }
                else
                {
                    assert(false&& "It is a in valid bool value name");
                }
            }
        };

    };

    static CType* Type=new CBoolType();
    return Type;
}




#define DEFINE_INT_TYPE(TypeName,Type) \
CType* CGetType<Type>:: operator() () \
{   \
    class CNumType: public CType  \
    { \
    public:  \
        CNumType() :CType(STypeID(TypeName,true), ETypeFlags::Basic | ETypeFlags::ScriptInner ) \
        { \
            Instancable=new CNumInstance(this); \
            StringSerializable=new CNumStringSerializable(); \
            Functions= new CFunctionList(this); \
            { \
                auto ToStringFunction = new CNativeFunction(Functions,U"ToString",CGetType<CString>()(),{},{}); \
                ToStringFunction->SetCppBody([](const TVector<CAny>& InArgs)->CAny  \
                { \
                    Type Value=**reinterpret_cast<const Type**>(InArgs[0].GetPointer()); \
                    return CString((int64_t)Value); \
                }); \
                Functions->VirtualFunctionTable.Add(ToStringFunction->ID); \
            } \
        } \
    protected: \
        class CNumInstance: public ITypeInstance \
        { \
        protected: \
            CType* NumType; \
        public: \
            CNumInstance(CType* InNumType) \
            { \
                NumType=InNumType; \
            } \
            virtual CString ToDebugString(const void * InInstance) const override \
            { \
                Type Value= *reinterpret_cast<const Type*>(InInstance); \
                return CString((int64_t)Value); \
            } \
            virtual uint32_t GetSize() override \
            { \
                return sizeof(Type); \
            } \
            virtual uint64_t GetInstanceHash(const void * Instance) const override \
            { \
                return *reinterpret_cast<const Type*>(Instance); \
            } \
            virtual bool IsForceConvertableTo(CType * Other) override \
            { \
                if(Other==NumType) \
                { \
                    return true; \
                } \
                if(Other->IsEnumType()) \
                { \
                    CEnumBase* EnumBase=static_cast<CEnumBase*>(Other); \
                    return IsForceConvertableTo(EnumBase->GetValueType()); \
                } \
                return false; \
            } \
            virtual bool IsInstanceEqual(const void * Instance0,const void * Instance1) const override \
            { \
                return *reinterpret_cast<const Type*>(Instance0)==*reinterpret_cast<const Type*>(Instance1); \
            } \
            virtual void InitInstance(void* Memory) override \
            { \
                *reinterpret_cast<Type*>(Memory)=0; \
            } \
            virtual void EraseInstance(void* Instance) override \
            { \
                /*do nothing*/ \
            } \
            virtual void CloneInstance(const void* Instance,void * TargetMemory) override \
            { \
                *reinterpret_cast<Type*>(TargetMemory)=*reinterpret_cast<const Type*>(Instance); \
            } \
            void * CreateInstance() override \
            { \
                return new Type(0); \
            } \
            void ResetAllocated(void * Memory) override \
            { \
                *reinterpret_cast<Type*>(Memory)=0; \
            } \
        }; \
        class CNumStringSerializable: public IStringSerializable \
        { \
        public: \
            virtual CString ToString(const void* InInstance) const override \
            { \
                Type Value= *reinterpret_cast<const Type*>(InInstance); \
                if constexpr (std::is_signed_v<Type>) \
                { \
                    return CString((int64_t)Value); \
                } \
                else \
                { \
                    return CString((uint64_t)Value); \
                } \
            } \
            virtual void FromString(const CString& InString,void * InInstance) const override \
            { \
                if constexpr (std::is_signed_v<Type>) \
                { \
                    *reinterpret_cast<Type*>(InInstance)=CString(InString).ToInt64(); \
                } \
                else \
                { \
                    *reinterpret_cast<Type*>(InInstance)=CString(InString).ToUInt64(); \
                } \
            } \
        }; \
    }; \
    static CType* Type=new CNumType(); \
    return Type;   \
};


//define num types
DEFINE_INT_TYPE(U"Int64",int64_t)
DEFINE_INT_TYPE(U"Int32",int32_t)
DEFINE_INT_TYPE(U"Int16",int16_t)
DEFINE_INT_TYPE(U"Int8",int8_t)
DEFINE_INT_TYPE(U"Uint64",uint64_t)
DEFINE_INT_TYPE(U"Uint32",uint32_t)
DEFINE_INT_TYPE(U"Uint16",uint16_t)
DEFINE_INT_TYPE(U"Uint8",uint8_t)

CType* CGetType<float>:: operator() ()
{

    class CFloatType: public CType
    {

    public:
        CFloatType()
            :CType(STypeID(U"Float32",true)
            , ETypeFlags::Basic | ETypeFlags::ScriptInner
            )
        {
            Instancable=new CFloatInstance(this);
            StringSerializable=new CFloatStringSerializable();
            Functions= new CFunctionList(this);
            {
                auto ToStringFunction = new CNativeFunction(
                    Functions
                    ,U"ToString"
                    ,CGetType<CString>()()
                    ,{}
                    ,{}
                    );
                ToStringFunction->SetCppBody([](const TVector<CAny>& InArgs)->CAny
                {
                    float Value=**reinterpret_cast<const float**>(InArgs[0].GetPointer());
                    return CString(Value);
                });
                Functions->VirtualFunctionTable.Add(ToStringFunction->ID);
            }
        }
    protected:
        class CFloatInstance: public ITypeInstance
        {
        protected:
            CType* FloatType;
        public:
            CFloatInstance(CType* InFloatType)
            {
                FloatType=InFloatType;
            }

            virtual CString ToDebugString(const void * InInstance) const override
            {
                float Value= *reinterpret_cast<const float*>(InInstance);
                return CString(Value);
            }

            virtual uint32_t GetSize() override
            {
                return sizeof(float);
            }

            virtual uint64_t GetInstanceHash(const void * Instance) const override
            {
                return *reinterpret_cast<const uint32_t*>(Instance);
            }
            
            virtual bool IsForceConvertableTo(CType * Other) override
            {
                if(Other==FloatType)
                {
                    return true;
                }
                return false;
            }

            virtual bool IsInstanceEqual(const void * Instance0,const void * Instance1) const override
            {
                return *reinterpret_cast<const float*>(Instance0)==*reinterpret_cast<const float*>(Instance1);
            }

            virtual void InitInstance(void* Memory) override
            {
                *reinterpret_cast<float*>(Memory)=0.f;
            }

            virtual void EraseInstance(void* Instance) override
            {
                //do nothing
            }

            virtual void CloneInstance(const void* Instance,void * TargetMemory) override
            {
                *reinterpret_cast<float*>(TargetMemory)=*reinterpret_cast<const float*>(Instance);
            }

            void * CreateInstance() override
            {
                return new float(0);
            }

            void ResetAllocated(void * Memory) override
            {
                *reinterpret_cast<float*>(Memory)=0.f;
            }

        };

        class CFloatStringSerializable: public IStringSerializable
        {
        public:
            virtual CString ToString(const void* InInstance) const override
            {
                float Value= *reinterpret_cast<const float*>(InInstance);
                return CString(Value);
            }
            virtual void FromString(const CString& InString,void * InInstance) const override
            {
                *reinterpret_cast<float*>(InInstance)=CString(InString).ToDouble();
            }
        };
    };


    static CType* Type=new CFloatType();

    return Type;  
}

CType* CGetType<double>:: operator() ()
{

    class CDoubleType: public CType
    {
    public:
        CDoubleType()
            :CType(STypeID(U"Float64",true)
        , ETypeFlags::Basic | ETypeFlags::ScriptInner
        )
        {
            Instancable=new CDoubleInstance(this);
            StringSerializable=new CDoubleStringSerializable();
            Functions= new CFunctionList(this);
            {
                auto ToStringFunction = new CNativeFunction(Functions,U"ToString",CGetType<CString>()(),{},{});
                ToStringFunction->SetCppBody([](const TVector<CAny>& InArgs)->CAny
                {
                    double Value=**reinterpret_cast<const double**>(InArgs[0].GetPointer());
                    return CString(Value);
                });
                Functions->VirtualFunctionTable.Add(ToStringFunction->ID);
            }
        }
    
    protected:
        class CDoubleInstance: public ITypeInstance
        {
        protected:
            CType* DoubleType;
        public:
            CDoubleInstance(CType* InDoubleType)
            {
                DoubleType=InDoubleType;
            }

            virtual CString ToDebugString(const void * InInstance) const override
            {
                double Value= *reinterpret_cast<const double*>(InInstance);
                return CString(Value);
            }

            virtual uint32_t GetSize() override
            {
                return sizeof(double);
            }

            virtual uint64_t GetInstanceHash(const void * Instance) const override
            {
                return *reinterpret_cast<const uint64_t*>(Instance);
            }

            virtual bool IsForceConvertableTo(CType * Other) override
            {
                if(Other==DoubleType)
                {
                    return true;
                }
                return false;
            }

            virtual bool IsInstanceEqual(const void * Instance0,const void * Instance1) const override
            {
                return *reinterpret_cast<const double*>(Instance0)==*reinterpret_cast<const double*>(Instance1);
            }

            virtual void InitInstance(void* Memory) override
            {
                *reinterpret_cast<double*>(Memory)=0;
            }

            virtual void EraseInstance(void* Instance) override
            {
                //do nothing
            }

            virtual void CloneInstance(const void* Instance,void * TargetMemory) override
            {
                *reinterpret_cast<double*>(TargetMemory)=*reinterpret_cast<const double*>(Instance);
            }

            void * CreateInstance() override
            {
                return new double(0);
            }

            void ResetAllocated(void * Memory) override
            {
                *reinterpret_cast<double*>(Memory)=0;
            }

        };

        class CDoubleStringSerializable: public IStringSerializable
        {
        public:
            virtual CString ToString(const void* InInstance) const override
            {
                double Value= *reinterpret_cast<const double*>(InInstance);
                return CString(Value);
            }
            virtual void FromString(const CString& InString,void * InInstance) const override
            {
                *reinterpret_cast<double*>(InInstance)=CString(InString).ToDouble();
            }
        };
    };
    static CType* Type=new CDoubleType();
    return Type;  
}



CType*  CGetType<char32_t>::operator()()
{
    class CCharType: public CType
    {

    public:
        CCharType()
            :CType(STypeID(U"UnicodeChar32",true), ETypeFlags::Basic | ETypeFlags::ScriptInner)
        {
            Instancable=new CCharInstance(this);
            StringSerializable=new CCharStringSerializable();
            Functions= new CFunctionList(this);
            {
                auto ToStringFunction = new CNativeFunction(
                    Functions
                    ,U"ToString"
                    ,CGetType<CString>()()
                    ,{}
                    ,{}
                    );
                ToStringFunction->SetCppBody([](const TVector<CAny>& InArgs)->CAny
                {
                    char32_t Value=**reinterpret_cast<const char32_t**>(InArgs[0].GetPointer());
                    return CString(Value);
                });

                Functions->VirtualFunctionTable.Add(ToStringFunction->ID);
            }
        }

    protected:
        class CCharInstance: public ITypeInstance
        {
        protected:
            CType* CharType;
        public:
            CCharInstance(CType* InCharType)
            {
                CharType=InCharType;
            }

            virtual CString ToDebugString(const void * InInstance) const override
            {
                char32_t Value= *reinterpret_cast<const char32_t*>(InInstance);
                return U"\'"+ CString(Value)+U"\'";
            }

            virtual uint32_t GetSize() override
            {
                return sizeof(char32_t);
            }

            virtual uint64_t GetInstanceHash(const void * Instance) const override
            {
                return *reinterpret_cast<const char32_t*>(Instance);
            }

            virtual bool IsForceConvertableTo(CType * Other) override
            {
                if(Other==CharType)
                {
                    return true;
                }
                return false;
            }

            virtual bool IsInstanceEqual(const void * Instance0,const void * Instance1) const override
            {
                return *reinterpret_cast<const char32_t*>(Instance0)==*reinterpret_cast<const char32_t*>(Instance1);
            }

            virtual void InitInstance(void* Memory) override
            {
                *reinterpret_cast<char32_t*>(Memory)=0;
            }

            virtual void EraseInstance(void* Instance) override
            {
                //do nothing
            }

            virtual void CloneInstance(const void* Instance,void * TargetMemory) override
            {
                *reinterpret_cast<char32_t*>(TargetMemory)=*reinterpret_cast<const char32_t*>(Instance);
            }

            void * CreateInstance() override
            {
                return new char32_t(0);
            }

            void ResetAllocated(void * Memory) override
            {
                *reinterpret_cast<char32_t*>(Memory)=0;
            }
        };

        class CCharStringSerializable: public IStringSerializable
        {
        public:
            virtual CString ToString(const void* InInstance) const override
            {
                char32_t Value= *reinterpret_cast<const char32_t*>(InInstance);
                return CString(Value);
            }
            virtual void FromString(const CString& InString,void * InInstance) const override
            {
                *reinterpret_cast<char32_t*>(InInstance)=CString(InString).GetData()[0];
            }
        };
    };

    static CType* Type=new CCharType();
    return Type;
}


CType*  CGetType<std::nullptr_t>::operator()()
{
    class CNullptrType:public CType
    {
    public:
        CNullptrType()
            :CType(STypeID(U"Nullptr",true), ETypeFlags::Basic | ETypeFlags::ScriptInner)
        {
            Instancable=new CNullptrInstance(this);
            Functions= new CFunctionList(this);
            {
            auto ToStringFunction = new CNativeFunction(
                    Functions
                    ,U"ToString"
                    ,CGetType<CString>()()
                    ,{}
                    ,{}
                    );
            ToStringFunction->SetCppBody([](const TVector<CAny>& InArgs)->CAny
            {
                    return CString(U"nullptr");
            });

            Functions->VirtualFunctionTable.Add(ToStringFunction->ID);
            }
        }

    protected:
        class CNullptrInstance: public ITypeInstance
        {
        protected:
            CType* NullptrType;
        public:
            CNullptrInstance(CType* InNullptrType)
            {
                NullptrType=InNullptrType;
            }

            virtual CString ToDebugString(const void * InInstance) const override
            {
                return U"nullptr";
            }

            virtual uint32_t GetSize() override
            {
                return sizeof(std::nullptr_t);
            }

            virtual uint64_t GetInstanceHash(const void * Instance) const override
            {
                return 0;
            }

            virtual bool IsForceConvertableTo(CType * Other) override
            {
                if(Other==NullptrType)
                {
                        return true;
                }
                return false;
            }

            virtual bool IsInstanceEqual(const void * Instance0,const void * Instance1) const override
            {
                return true;
            }

            virtual void InitInstance(void* Memory) override
            {
                *reinterpret_cast<std::nullptr_t*>(Memory)=nullptr;
            }

            virtual void EraseInstance(void* Instance) override
            {
                //do nothing
            }

            virtual void CloneInstance(const void* Instance,void * TargetMemory) override
            {
                *reinterpret_cast<std::nullptr_t*>(TargetMemory)=*reinterpret_cast<const std::nullptr_t*>(Instance);
            }

            void * CreateInstance() override
            {
                return new std::nullptr_t(nullptr);
            }

            void ResetAllocated(void * Memory) override
            {
                *reinterpret_cast<std::nullptr_t*>(Memory)=nullptr;
            }
        };
   
   
   };

    static CType* Type=new CNullptrType();
    return Type;
}


CType*  CGetType<void>::operator()()
{
    class CVoidType:public CType
    {
    public:
        CVoidType()
            :CType(STypeID(U"Void",true), ETypeFlags::Basic | ETypeFlags::ScriptInner | ETypeFlags::Void)
        {
            //have no instance/property/function
        }
    };

    static CType* Type=new CVoidType();
    return Type;
}

static uint8_t RegisterTypes()
{
    CType* Types[]=
    {
        CGetType<bool>()(),
        CGetType<int64_t>()(),
        CGetType<int32_t>()(),
        CGetType<int16_t>()(),
        CGetType<int8_t>()(),
        CGetType<uint64_t>()(),
        CGetType<uint32_t>()(),
        CGetType<uint16_t>()(),
        CGetType<uint8_t>()(),
        CGetType<float>()(),
        CGetType<double>()(),
        CGetType<CString>()(),
        CGetType<char32_t>()(),
        CGetType<std::nullptr_t>()(),
        CGetType<void>()(),
    };

    return 0;
}

static uint8_t RegisterTypesCaller=RegisterTypes();
